package com.kongjs.application.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kongjs.application.convert.GroupsConverter;
import com.kongjs.application.exception.ApiParamCheckException;
import com.kongjs.application.mapper.GroupsMapper;
import com.kongjs.application.model.dto.QueryGroupDTO;
import com.kongjs.application.model.dto.QueryGroupParamDTO;
import com.kongjs.application.model.dto.SaveGroupDTO;
import com.kongjs.application.model.dto.UpdateGroupDTO;
import com.kongjs.application.model.entity.Groups;
import com.kongjs.application.model.entity.Roles;
import com.kongjs.application.model.entity.UserGroup;
import com.kongjs.application.service.IGroupsService;
import com.kongjs.application.service.IUserGroupService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Transactional
@Service
public class GroupsServiceImpl extends ServiceImpl<GroupsMapper, Groups> implements IGroupsService {
    @Resource
    private GroupsConverter groupsConverter;
    @Resource
    private IUserGroupService userGroupService;

    @Override
    public boolean save(SaveGroupDTO dto) {
        Groups groups = groupsConverter.toEntity(dto);
        return save(groups);
    }

    @Override
    public boolean remove(Serializable id) {
        userGroupService.lambdaUpdate()
                .eq(UserGroup::getGroupId, id)
                .remove();
        return removeById(id);
    }

    @Override
    public boolean update(UpdateGroupDTO dto) {
        if (!ObjectUtils.isEmpty(dto.getParentId())) {
            if (dto.getId().equals(dto.getParentId())){
                throw new ApiParamCheckException("设置的上级部门不能与当前部门相同");
            }
            List<Groups> groups = lambdaQuery().eq(Groups::getEnabled, 1).list();
            List<TreeNode<Long>> treeNodes = new ArrayList<>();
            for (Groups group : groups) {
                TreeNode<Long> node = new TreeNode<>();
                node.setId(group.getId());
                node.setParentId(dto.getParentId());
                treeNodes.add(node);
            }
            if (!CollectionUtils.isEmpty(treeNodes)){
                List<Tree<Long>> trees = TreeUtil.build(treeNodes, null);
                if (!CollectionUtils.isEmpty(trees)){
                    for (Tree<Long> tree : trees) {
                        Tree<Long> parentNode = TreeUtil.getNode(tree, dto.getParentId());
                        if (ObjectUtils.isEmpty(parentNode)){
                            continue;
                        }
                        List<Long> parentsId = TreeUtil.getParentsId(parentNode, false);
                        // 要设置父级节点存在当前节点作为某个上级,循环引用
                        if (parentsId.contains(dto.getId())) {
                            throw new ApiParamCheckException("设置的上级部门不能是当前部门的下级");
                        }
                    }
                }
            }
        }
        Groups groups = groupsConverter.toEntity(dto);
        return updateById(groups);
    }

    @Override
    public QueryGroupDTO query(Serializable id) {
        Groups groups = getById(id);
        return groupsConverter.toDto(groups);
    }

    @Override
    public List<QueryGroupDTO> querylist(QueryGroupParamDTO dto) {
        List<Groups> groups = lambdaQuery()
                .like(StringUtils.hasText(dto.getGroupName()), Groups::getGroupName, dto.getGroupName())
                .list();
        return groupsConverter.toDtos(groups);
    }

    @Override
    public List<QueryGroupDTO> trees(QueryGroupParamDTO dto) {
        List<Groups> groups = lambdaQuery()
                .like(StringUtils.hasText(dto.getGroupName()), Groups::getGroupName, dto.getGroupName())
                .eq(Groups::getEnabled, 1)
                .list();
        return groupsConverter.toDtos(groups);
    }
}
